// Parser.cpp	-	Parser class
// Parses two text files and creates a data structure of Nodes.
// The Nodes are stored in a unordered_map<string, Node*>.

#include <iostream>
#include <fstream>
#include <sstream>
#include "Parser.h"
typedef std::pair<std::string, Node*> NodeMapPair;

Parser::Parser(void)
{
}

Parser::~Parser(void)
{
}

// Allocates memory for an unordered_map<string, Node*> (typedef'd as NodeMap)
// Calls the two parser functions and passes the map by reference, then
// returns the address of the NodeMap.
NodeMap* Parser::parseData(std::string locsFilename, std::string connsFilename, std::string pointToExclude)
{
    NodeMap *nodeListPtr = new NodeMap;
    parseLocations(locsFilename, nodeListPtr, pointToExclude);
    parseConnections(connsFilename, nodeListPtr, pointToExclude);
    return nodeListPtr;
}

// Parses a text file holding node names and X,Y coordinates.
// The text file must have this format:
// A1 30 48
// A2 30 178
// A3 30 483
// END
void Parser::parseLocations(std::string filename, NodeMap *nodeMapPtr, std::string pointToExclude)
{
	std::ifstream inFile(filename.c_str(), std::ios::in);
	std::string name;
	int x;
	int y;
	while (!inFile.eof())
	{
		inFile >> name >> x >> y;
		if (name == "END")	//Reached end of locations file
			break;
		if (name == pointToExclude) //Line is the point to exclude
			continue;
		else
		{
			nodeMapPtr->insert(NodeMapPair(name, (new Node(name, x, y))));
		}
	}
}

// Parses a text file holding the node name, number of connections, and
// the names of each connection. The text file must have this format:
// A1 2 B1 A2
// A2 3 A1 B2 A4
// A3 3 A2 B5 A5
// END
void Parser::parseConnections(std::string filename, NodeMap *nodeMapPtr, std::string pointToExclude)
{
	std::ifstream inFile(filename.c_str(), std::ios::in);
	std::string buffer1;
	std::string buffer2;
	std::vector<std::string> pieces;
	while (!inFile.eof())
	{
		getline(inFile, buffer1);
		pieces.clear();
		std::stringstream ss(buffer1);
		bool excludedLineFound = false;
		while (ss >> buffer2)
		{
			if (buffer2 == pointToExclude && pieces.size() == 0)
			{
				excludedLineFound = true;
				break;
			}
			else if (buffer2 == pointToExclude)
			{
				continue;
			}
			pieces.push_back(buffer2);
		}

		if (excludedLineFound)
			continue;
		if (pieces.at(0) == "END")	//Reached end of connections file
			break;

		//Add the new connections to the Node pointed to by this iterator
		NodeMap::iterator itrForNode = nodeMapPtr->find(pieces.at(0));
		for (size_t j = 2; j < pieces.size(); ++j)
		{
			//This iterator points to the Nodes we want to add as new connections
			NodeMap::iterator itrForNewConnection = nodeMapPtr->find(pieces.at(j));

			if (itrForNewConnection == nodeMapPtr->end())
				std::cout << "Node " << pieces.at(j) << " not found in NodeMap by parseConnections()." << std::endl;

			itrForNode->second->addConnection(itrForNewConnection->second);
		}
	}
}
